// Time Tracker by Eric Nadeau (nado18@gmail.com)
// Copyright (C) 2007 by Eric Nadeau
// Distributed under the terms of the GNU General Public License (see GPL.txt)

package model;

import java.io.*;
import java.util.*;

import javax.swing.event.*;
import javax.swing.table.*;

/**
 * @author Eric Nadeau (nado18@gmail.com), on Apr 21, 2004
 */
public class ProjectTableModel extends DefaultTableModel {
	private static final int COLUMN_ACTIVE = 0;
	private static final int COLUMN_NAME = 1;
	private static final int COLUMN_TIME = 2;
	private static final int KEY_COLUMN = COLUMN_NAME;
	
	private Vector<Project> projects = new Vector<Project>();
	private HashSet<TableModelListener> listeners = new HashSet<TableModelListener>();
	
	public ProjectTableModel() {
		super(new String[]{
				"Active",
				"Description",
				"Time"
		}, 0);
	}
	
	/* (non-Javadoc)
	 * @see javax.swing.table.TableModel#getRowCount()
	 */
	public int getRowCount() {
		if( projects != null ) {
			return projects.size();
		}
		else {
			return 0;
		}
	}

	/* (non-Javadoc)
	 * @see javax.swing.table.TableModel#getColumnClass(int)
	 */
	public Class<?> getColumnClass(int columnIndex) {
		switch (columnIndex) {
			case COLUMN_ACTIVE:
				return Boolean.class;
			default:
				return String.class;
		}
	}

	/* (non-Javadoc)
	 * @see javax.swing.table.TableModel#isCellEditable(int, int)
	 */
	public boolean isCellEditable(int rowIndex, int columnIndex) {
		return columnIndex == COLUMN_ACTIVE;
	}

	/* (non-Javadoc)
	 * @see javax.swing.table.TableModel#setValueAt(java.lang.Object, int, int)
	 */
	public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
		if( (columnIndex == COLUMN_ACTIVE) && (rowIndex>=0) && (rowIndex<getRowCount()) ) {
			Project p = (Project)getValueAt(rowIndex, KEY_COLUMN);
			if( ((Boolean)aValue).booleanValue() ) {
				p.start();
			}
			else {
				p.stop();
			}
		}
		
		notifyListeners(rowIndex);
	}
	
	private void notifyListeners() {
		TableModelEvent tme = new TableModelEvent(this);
		notifyListeners(tme);
	}
	
	private void notifyListeners(int row) {
		TableModelEvent tme = new TableModelEvent(this, row);
		notifyListeners(tme);
	}
	
	private void notifyListeners(TableModelEvent ev) {
		for (Iterator iter = listeners.iterator(); iter.hasNext();) {
			TableModelListener tml = (TableModelListener) iter.next();
			tml.tableChanged(ev);
		}
	}
	
	public void loadProjectsFromFile(String filename) throws Exception {
		BufferedReader br = null;
		try {
			Vector<Project> projects = new Vector<Project>();
			br = new BufferedReader( new FileReader(filename) );
			
			String line = "";
			while( (line=br.readLine()) != null ) {
				projects.add( Project.loadString(line) );
			}
			
			br.close();
			setProjects(projects);
		}
		catch (Exception ex) {
			throw ex;
		}
		finally {
			if( br != null ) {
				try {
					br.close();
				}
				catch (IOException ex) {}
			}
		}
	}
	
	public void saveProjectsToFile(String filename) throws IOException {
		PrintWriter pw = null;
		try {
			pw = new PrintWriter( new FileWriter(filename) );
			for (Iterator iter = projects.iterator(); iter.hasNext();) {
				Project p = (Project)iter.next();
				pw.println( p.saveString() );
			}
		}
		catch (IOException ex) {
			throw(ex);
		}
		finally {
			if( pw != null ) {
				pw.flush();
				pw.close();
			}
		}
	}
	
	private void setProjects(Vector<Project> someProjects) {
		projects.clear();
		projects.addAll(someProjects);
		Collections.sort(projects);
		notifyListeners();
	}
	
	public void addProject(Project p) {
		if( p != null ) {
			projects.add(p);
			Collections.sort(projects);
			notifyListeners();
		}
	}
	
	public void removeProject(Project p) {
		if( projects.remove(p) ) {
			notifyListeners();
		}
	}
	
	public void editedProject(Project p) {
		int row = projects.indexOf(p);
		if( row >= 0 ) {
			notifyListeners(row);
		}
	}
	
	private boolean isValidRow(int row) {
		return (row>=0) && (row<getRowCount());
	}
	
	private boolean isValidColumn(int col) {
		return (col>=0) && (col<getColumnCount());
	}
	
	private boolean isValidCell(int row, int col) {
		return isValidRow(row) && isValidColumn(col);
	}
	
	public Object getValueAt(int row, int column) {
		if( isValidCell(row, column) ) {
			Project p = (Project)projects.elementAt(row);
			switch(column) {
				case COLUMN_ACTIVE:
					return Boolean.valueOf(p.isActive());
				case COLUMN_NAME:
					return p;
				case COLUMN_TIME:
					return TimeConverter.longToString( p.getElapsed() );
				default:
					return null;
				}
		}
		else {
			return null;
		}
	}
	
	public void addTableModelListener(TableModelListener l) {
		listeners.add(l);
	}
	public void removeTableModelListener(TableModelListener l) {
		listeners.remove(l);
	}
	
	public double getBill() {
		double sum = 0;
		for (Iterator iter = projects.iterator(); iter.hasNext();) {
			Project p = (Project) iter.next();
			String price = p.getBillPrice();
			try {
				double d = Double.parseDouble(price);
				sum += d;
			}
			catch(Exception ex) {}
		}
		return sum;
	}
}
